package com.pioneer.cloudstorage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pioneer.cloudstorage.common.constant.MessageConstant;
import com.pioneer.cloudstorage.common.exception.PasswordErrorException;
import com.pioneer.cloudstorage.common.exception.AccountNotFoundException;
import com.pioneer.cloudstorage.mapper.UsersMapper;
import com.pioneer.cloudstorage.pojo.dto.UserDTO;
import com.pioneer.cloudstorage.pojo.entity.FileContentIndex;
import com.pioneer.cloudstorage.pojo.entity.FileMetadata;
import com.pioneer.cloudstorage.pojo.entity.User;
import com.pioneer.cloudstorage.pojo.vo.SearchFileVO;
import com.pioneer.cloudstorage.pojo.vo.UserInfoVO;
import com.pioneer.cloudstorage.service.UsersService;
import com.pioneer.cloudstorage.utils.BaseContext;
import com.pioneer.cloudstorage.utils.FileContentMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.pioneer.cloudstorage.utils.BCryptUtils.encryptPassword;
import static com.pioneer.cloudstorage.utils.BCryptUtils.matchesPassword;

@Service
@Slf4j
public class UsersServiceImpl extends ServiceImpl<UsersMapper, User> implements UsersService {
    @Autowired
    private UsersMapper usersMapper;
    @Autowired
    private FileContentMapper fileContentRepository;
    @Override
    public void register(UserDTO userDTO) {
        User user = new User();
        BeanUtil.copyProperties(userDTO,user);
       String password = encryptPassword(user.getPassword());
        user.setPassword(password);
        usersMapper.insert(user);
    }

    @Override
    public User login(UserDTO userDTO)  {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername, userDTO.getUsername());
         User user = getOne(lambdaQueryWrapper);
        if (user == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        if (!matchesPassword(userDTO.getPassword(), user.getPassword())) {
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
          return user;
    }
  @Override
  public UserInfoVO info() {
        Long id= BaseContext.getCurrentId();
        User user = usersMapper.selectById(id);
      UserInfoVO userInfoVO = UserInfoVO.builder()
              .username(user.getUsername())
              .email(user.getEmail())
              .id(user.getId())
              .build();
     return userInfoVO;
  }



    @Autowired
    private ElasticsearchOperations elasticsearchOperations;
        @Override
        public List<SearchFileVO> searchFiles(Long userId, String keyword) {
            if (!StringUtils.hasText(keyword)) {
                throw new RuntimeException("搜索关键词不能为空");
            }

            log.info("用户 {} 搜索文件，关键词: {}", userId, keyword);

            try {
                // 同时搜索文件名和文件内容
                List<SearchFileVO> fileNameResults = searchByFileName(userId, keyword);
                List<SearchFileVO> fileContentResults = searchByFileContent(userId, keyword);

                // 合并结果，去重（优先保留文件名匹配的结果）
                Map<Long, SearchFileVO> resultMap = new LinkedHashMap<>();

                // 先添加文件名搜索结果（通常更相关）
                for (SearchFileVO result : fileNameResults) {
                    resultMap.put(result.getId(), result);
                }

                // 再添加内容搜索结果，不覆盖已存在的文件名匹配结果
                for (SearchFileVO result : fileContentResults) {
                    resultMap.putIfAbsent(result.getId(), result);
                }

                List<SearchFileVO> results = new ArrayList<>(resultMap.values());

                log.info("搜索完成，用户: {}, 关键词: {}, 结果数量: {}", userId, keyword, results.size());
                return results;

            } catch (Exception e) {
                log.error("搜索文件失败，用户: {}, 关键词: {}", userId, keyword, e);
                throw new RuntimeException("搜索失败");
            }
        }

        /**
         * 搜索文件名 - MySQL LIKE 模糊查询
         */
        private List<SearchFileVO> searchByFileName(Long userId, String keyword) {
            log.debug("执行文件名搜索，用户: {}, 关键词: {}", userId, keyword);

            try {
                List<FileMetadata> fileMetadatas = usersMapper.selectByFileName(userId, keyword);
                return fileMetadatas.stream()
                        .map(this::convertToSearchFileVO)
                        .collect(Collectors.toList());
            } catch (Exception e) {
                log.error("文件名搜索失败", e);
                return new ArrayList<>();
            }
        }

        /**
         * 搜索文件内容 - Elasticsearch 搜索（使用原生查询避免转换问题）
         */
        private List<SearchFileVO> searchByFileContent(Long userId, String keyword) {
            log.debug("执行文件内容搜索，用户: {}, 关键词: {}", userId, keyword);

            try {
                // 方法1：使用 CriteriaQuery 避免 Repository 的转换问题
                Criteria criteria = new Criteria("userId").is(userId)
                        .and("content").contains(keyword);

                CriteriaQuery query = new CriteriaQuery(criteria);
                SearchHits<FileContentIndex> searchHits = elasticsearchOperations.search(query, FileContentIndex.class);

                if (searchHits.isEmpty()) {
                    return new ArrayList<>();
                }

                // 获取对应的文件ID列表
                List<Long> fileIds = searchHits.getSearchHits().stream()
                        .map(SearchHit::getContent)
                        .map(FileContentIndex::getFileId)
                        .collect(Collectors.toList());

                // 从 MySQL 查询文件详细信息
                List<FileMetadata> fileMetadatas = usersMapper.selectBatchIds(fileIds);

                // 转换为 Map 便于查找
                Map<Long, FileMetadata> metadataMap = fileMetadatas.stream()
                        .collect(Collectors.toMap(FileMetadata::getId, fm -> fm));

                // 合并结果，确保用户权限
                List<SearchFileVO> results = new ArrayList<>();
                for (SearchHit<FileContentIndex> hit : searchHits.getSearchHits()) {
                    FileContentIndex contentIndex = hit.getContent();
                    FileMetadata metadata = metadataMap.get(contentIndex.getFileId());
                    if (metadata != null && metadata.getUserId().equals(userId)) {
                        results.add(convertToSearchFileVO(metadata));
                    }
                }

                return results;

            } catch (Exception e) {
                log.error("文件内容搜索失败，用户: {}, 关键词: {}", userId, keyword, e);
                // 不抛出异常，返回空列表，让文件名搜索继续工作
                return new ArrayList<>();
            }
        }

        /**
         * 备用的文件内容搜索方法（如果上面方法还有问题）
         */
        private List<SearchFileVO> searchByFileContentAlternative(Long userId, String keyword) {
            log.debug("执行备用文件内容搜索，用户: {}, 关键词: {}", userId, keyword);

            try {
                // 直接使用低级别查询，避免实体转换
                String query = """
            {
                "query": {
                    "bool": {
                        "must": [
                            {
                                "term": {
                                    "userId": %d
                                }
                            },
                            {
                                "match": {
                                    "content": "%s"
                                }
                            }
                        ]
                    }
                },
                "_source": ["fileId"]
            }
            """.formatted(userId, keyword);

                // 这里需要实现原生查询，具体实现取决于你的 Elasticsearch 版本
                // 暂时返回空列表，让搜索功能至少能工作
                log.warn("使用备用搜索方法，暂时返回空结果");
                return new ArrayList<>();

            } catch (Exception e) {
                log.error("备用文件内容搜索也失败", e);
                return new ArrayList<>();
            }
        }

        /**
         * 转换 FileMetadata 为 SearchFileVO
         */
        private SearchFileVO convertToSearchFileVO(FileMetadata fileMetadata) {
            SearchFileVO vo = new SearchFileVO();
            vo.setId(fileMetadata.getId());
            vo.setFileName(fileMetadata.getFileName());
            vo.setFilePath(fileMetadata.getFilePath());
            vo.setCreatedTime(fileMetadata.getCreatedTime());
            vo.setUpdatedTime(fileMetadata.getUpdatedTime());
            vo.setFileSize(fileMetadata.getFileSize());
            vo.setMimeType(fileMetadata.getMimeType());
            vo.setIsDirectory(fileMetadata.getIsDirectory());
            return vo;
        }
    }



